package com.example.demo;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.util.ClassUtils;

public class testProxy<T> implements InvocationHandler, MethodInterceptor{
	
	private Object subject;
	
	public testProxy(Object subject) {
		super();
		this.setSubject(subject);
	}
	
	private void befor(Object proxy, Method method, Object[] args) {
		System.out.println("befor");
		
	}
	private void after(Object proxy, Method method, Object[] args) {
		System.out.println("after");
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		Object ret = method.getName() + ": " + Arrays.toString(args);
		befor(proxy, method, args);
		if (this.subject != null && !this.subject.getClass().isInterface()) {
			ret = method.invoke(this.subject, args);
		}
		after(proxy, method, args);
		return ret;
	}

	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy arg3) throws Throwable {
		// TODO Auto-generated method stub
		Object ret = method.getName() + ": " + Arrays.toString(args);
		befor(proxy, method, args);
		if (this.subject != null && !this.subject.getClass().isInterface()) {
			ret = method.invoke(this.subject, args);
		}
		after(proxy, method, args);
		return ret;
	}
	/** 
      * 创建代理对象 
      *  
      * @param target 
      * @return 
      */  
     public Object getCglibInstance() {  
         Enhancer enhancer = new Enhancer();  
         enhancer.setSuperclass(this.subject.getClass());  
         // 回调方法  
         enhancer.setCallback(this);  
         // 创建代理对象  
         return enhancer.create();  
     }  
	
	
	public static Object get(Class<?> c) throws ClassNotFoundException, LinkageError, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {

		Object op = null;
		testProxy<Object> testProxy1 = new testProxy<Object>(null);

		
		if (c.isInterface()) {
			op = Proxy.newProxyInstance(c.getClassLoader(), new Class[] {c}, testProxy1);
			return op;
		}
		op = c.newInstance();
		testProxy1.setSubject(op);
		if (c.getInterfaces().length > 0) {
			op = Proxy.newProxyInstance(c.getClassLoader(), c.getInterfaces(), testProxy1);
		}
		op = testProxy1.getCglibInstance();
		return op;
	}
	
	private static ConcurrentHashMap<String, Object> bean = new ConcurrentHashMap<>();
	
	public static void init(Class<?> clazz, Object o) {
		String name = clazz.getPackage().getName();
		scanningFile scanningFile = new scanningFile(name);
		scanningFile.addClass();
		
		
		List<Class<? extends String>> eleStrategyList = scanningFile.getEleStrategyList();
		eleStrategyList.forEach((v)->{
			if (v.getAnnotation(myMapper.class) != null) {
				try {
//					System.out.println(v.getName());
					bean.put(v.getName(), get(v));
				} catch (Exception e) {e.printStackTrace();} 
			}
		});


		System.out.println("---------------------------------------------------------");
		Field[] fields = o.getClass().getDeclaredFields();
		for (Field field : fields) {
//			System.out.println(field.getGenericType().getTypeName());
//			System.out.println(bean.get(field.getGenericType().getTypeName()));
			if (field.getAnnotation(testProxy.Autowired.class) != null && bean.get(field.getGenericType().getTypeName()) != null) {
				field.setAccessible(true);
				try {
					field.set(o, bean.get(field.getGenericType().getTypeName()));
				} catch (IllegalArgumentException | IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	

	public Object getSubject() {
		return subject;
	}

	public void setSubject(Object subject) {
		this.subject = subject;
	}


	@Documented
	@Inherited
	@Retention(RUNTIME)
	@Target({ FIELD })
	public @interface Autowired{
		
	}
	
	@Documented
	@Inherited
	@Retention(RUNTIME)
	@Target({ TYPE, METHOD, FIELD, PARAMETER })
	public @interface myMapper {

	}

}
